CFrame library
Objects should be positioned, and rotated with CFrame. CFrame is a library built for working with position and rotation of an object in a 3D space, and has multiple different constructors for working with it.
CFrame.new
CFrame.new will return a CFrame object that you can change the properties, and arguments of to give it different mechanics. This, however, isn't going to be a full CFrame tutorial, so that you can mess with on your own time. For now, all you need to know is that CFrame.new is how you can create a new CFrame value.
It pretty much works the same way as Vector3 (in terms of position), with these exceptions:
CFrame does not avoid obstructions when positioning an object (unlike using Position and Vector3), therefore it has the ability to position objects anywhere, regardless of collision.
CFrame can take multiple different orders of arguments, or argument data types that will alter how something is positioned / rotated.
Here's an example:
local part = Instance.new("Part", workspace)
part.CFrame = CFrame.new(0, 5, 0)
As you can see, you could give it a set of coordinates just like Position and Vector3, and it will work the same way (obviously, with considering the differences between the two stated in the list of exceptions above).
CFrame.Angles
Despite mentioning how rotation can be altered by passing extra arguments to CFrame.new, most people prefer using the CFrame.Angles constructor to work with rotation (in most generic cases), because of it's simplicity to work with and understand. You should note, however, CFrame.Angles cannot be used to set the CFrame property of an object. Only CFrame.new may do this. This is because other constructors besides CFrame.new are actually meant to alter a currently existing CFrame.
This alteration is done by multiplying CFrame objects together, to add / subtract position and rotation (much like adding or subtracting one Vector3 value from another). Here's an example:
local part = Instance.new("Part", workspace)
part.CFrame = CFrame.new(0, 5, 0) * CFrame.Angles()
But what arguments does CFrame.Angles take? Well, numbers, obviously. But it's important to know what kind.
Rotation and Radians
A radian is the unit of an angle. Take for example, pi, which is meant to be half of a 360 degree rotation represented by the numbers 3.1415... which goes on infinitely, or just shortened to 3.14. This is because pi is represented in radians.
Lua's math library provides some pretty handy functions for dealing with degrees and radians, and even gives us the value of pi. This can be very useful for just about anything geometric, or dealing with circles and rotation.
So let's say for example, you wanted to rotate an object 180 degrees on it's X axis. You could simply just pass the value of pi to it's respective position in CFrame.Angles, like so:
local part = Instance.new("Part", workspace)
part.CFrame = CFrame.new(0, 5, 0) * CFrame.Angles(math.pi, 0, 0)
That's the gist of it. Alternatively, you can set the CFrame of one object, to exactly that of another just by assigning it to the CFrame property directly. This assignment will copy everything about the operand CFrame (including rotation), making it practical to use in situations where you want to copy the exact position and rotation of an object, in a very short compact way. Here's an example:
local part1 = Instance.new("Part", workspace)
local part2 = Instance.new("Part", workspace)
part1.CFrame = part1.CFrame * CFrame.Angles(math.pi, 0, 0)
part2.CFrame = part1.CFrame
That's about all I'm going to cover in this answer, but if you'd like to know more, just let me know and I'll respond with an updated answer and some informative links. Hope this helped!